#include "cheetah/graphics/program_glsl.h"

#include "cheetah/core/error.h"
#include "cheetah/graphics/utils.h"
#include "cheetah/graphics/shader_object.h"

namespace cheetah {
namespace graphics {
using namespace core;
ProgramGLSL::ProgramGLSL() : is_linked_(false), program_id_(0) {
  program_id_ = glCreateProgram();
  if (0 == program_id_) CheckErrorsGL("ProgramGLSL::ProgramGLSL");
}

ProgramGLSL::~ProgramGLSL(void) {
  if (0 != program_id_) glDeleteProgram(program_id_);
}

void ProgramGLSL::Begin() const { glUseProgram(program_id_); }
void ProgramGLSL::End() const { 
  //it should check that whether current program is in use, 
  //just neglected here in case of performance degradation
  glUseProgram(0); 
}
void ProgramGLSL::Disable() {
  glUseProgram(0);
}

void ProgramGLSL::PrintLinkLog() const {
  GLint len = 0;	
  glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH , &len);
  if(len <= 1) return;
  char *link_log = new char[len + 1];
  glGetProgramInfoLog(program_id_, len, &len, link_log);
  link_log[len] = 0;
  Error("ProgramGLSL::PrintLInkLog, %s", link_log);
  delete link_log;
}

bool ProgramGLSL::CheckLinkLog() {
  GLint status;
  glGetProgramiv(program_id_, GL_LINK_STATUS, &status);
  if (GL_TRUE == status) is_linked_ = true;
  if (!is_linked_) PrintLinkLog();
  return is_linked_;
}

bool ProgramGLSL::Link() {
  glLinkProgram(program_id_);
  return CheckLinkLog();
}

void ProgramGLSL::AttachShader(const ShaderObject &shader) const {
  if (shader.is_valid()) {
    glAttachShader(program_id_, shader.shader_id());
  }
}

void ProgramGLSL::DetachShader(const ShaderObject &shader) const {
  if (shader.is_valid()) {
    glDetachShader(program_id_, shader.shader_id());
  }
}

bool ProgramGLSL::Load(const char *vertex_shader, const char *fragment_shader) {
  if (NULL != vertex_shader) {
    ShaderObject so(GL_VERTEX_SHADER, vertex_shader, kFileSource);
    if (!so.is_valid()) return false;
    this->AttachShader(so);
  }
  if (NULL != fragment_shader) {
    ShaderObject so(GL_FRAGMENT_SHADER, fragment_shader, kFileSource);
    if (!so.is_valid()) return false;
    this->AttachShader(so);
  }
  return true;
}
} // graphics
} // cheetah
